"""
CMDB与Zabbix同步服务
实现主机数据同步到Zabbix，监控状态回显到CMDB
"""
import logging
from typing import Dict, Any, List, Optional
from django.utils import timezone
from django.db import transaction
from cmdb.models import Host
from ..models import ZabbixServer, MonitoringHost, MonitoringAlert
from .zabbix_api import ZabbixAPIManager

logger = logging.getLogger(__name__)


class CMDBZabbixSyncService:
    """CMDB与Zabbix同步服务"""

    def __init__(self, zabbix_server: ZabbixServer):
        """
        初始化同步服务

        Args:
            zabbix_server: Zabbix服务器实例
        """
        self.zabbix_server = zabbix_server
        self.api_manager = ZabbixAPIManager(zabbix_server)

    def sync_hosts_to_zabbix(self, host_ids: Optional[List[int]] = None) -> Dict[str, Any]:
        """
        同步CMDB主机到Zabbix

        Args:
            host_ids: 指定要同步的主机ID列表，为None时同步所有活跃主机

        Returns:
            同步结果
        """
        try:
            # 获取要同步的主机
            if host_ids:
                hosts = Host.objects.filter(id__in=host_ids)
            else:
                hosts = Host.objects.all()

            sync_results = []
            success_count = 0
            error_count = 0

            for host in hosts:
                try:
                    result = self._sync_single_host_to_zabbix(host)
                    sync_results.append(result)

                    if result['status'] == 'success':
                        success_count += 1
                    else:
                        error_count += 1

                except Exception as e:
                    error_result = {
                        'hostname': host.hostname,
                        'status': 'error',
                        'message': str(e)
                    }
                    sync_results.append(error_result)
                    error_count += 1
                    logger.error(f"同步主机 {host.hostname} 失败: {e}")

            return {
                'success': True,
                'data': {
                    'total_hosts': len(hosts),
                    'success_count': success_count,
                    'error_count': error_count,
                    'results': sync_results
                },
                'message': f'同步完成，成功: {success_count}, 失败: {error_count}'
            }

        except Exception as e:
            logger.error(f"批量同步主机失败: {e}")
            return {
                'success': False,
                'error': str(e)
            }

    def _sync_single_host_to_zabbix(self, host: Host) -> Dict[str, Any]:
        """
        同步单个主机到Zabbix

        Args:
            host: CMDB主机实例

        Returns:
            同步结果
        """
        try:
            # 检查主机是否已在Zabbix中存在
            existing_hosts = self.api_manager.get_hosts(filter={'host': host.hostname})

            if not existing_hosts['success']:
                return {
                    'hostname': host.hostname,
                    'status': 'error',
                    'message': f"查询Zabbix主机失败: {existing_hosts.get('error')}"
                }

            monitoring_host = None

            if existing_hosts['data']:
                # 主机已存在，更新监控记录
                zabbix_host = existing_hosts['data'][0]
                monitoring_host, created = MonitoringHost.objects.get_or_create(
                    host=host,
                    zabbix_server=self.zabbix_server,
                    defaults={
                        'zabbix_host_id': zabbix_host['hostid'],
                        'zabbix_host_name': zabbix_host['host'],
                        'monitoring_status': 'monitoring',
                        'availability': zabbix_host.get('available', '0'),
                        'last_check_time': timezone.now()
                    }
                )

                if not created:
                    # 更新现有记录
                    monitoring_host.zabbix_host_id = zabbix_host['hostid']
                    monitoring_host.zabbix_host_name = zabbix_host['host']
                    monitoring_host.monitoring_status = 'monitoring'
                    monitoring_host.availability = zabbix_host.get('available', '0')
                    monitoring_host.last_check_time = timezone.now()
                    monitoring_host.save()

                return {
                    'hostname': host.hostname,
                    'status': 'success',
                    'action': 'updated',
                    'message': '主机已存在，更新监控记录',
                    'zabbix_host_id': zabbix_host['hostid']
                }
            else:
                # 主机不存在，创建新主机
                return self._create_host_in_zabbix(host)

        except Exception as e:
            logger.error(f"同步主机 {host.hostname} 失败: {e}")
            return {
                'hostname': host.hostname,
                'status': 'error',
                'message': str(e)
            }

    def _create_host_in_zabbix(self, host: Host) -> Dict[str, Any]:
        """
        在Zabbix中创建新主机

        Args:
            host: CMDB主机实例

        Returns:
            创建结果
        """
        try:
            # 获取默认主机组（如果不存在则创建）
            default_group = self._get_or_create_default_hostgroup()
            if not default_group:
                return {
                    'hostname': host.hostname,
                    'status': 'error',
                    'message': '无法获取或创建默认主机组'
                }

            # 准备主机数据
            host_data = {
                'host': host.hostname,
                'name': host.hostname,
                'groups': [{'groupid': default_group['groupid']}],
                'interfaces': [
                    {
                        'type': 1,  # Agent interface
                        'main': 1,
                        'useip': 1,
                        'ip': host.private_ip or host.public_ip,
                        'dns': '',
                        'port': '10050'
                    }
                ],
                'templates': self._get_default_templates(),
                'status': 0,  # Monitored
                'inventory_mode': 1  # Automatic
            }

            # 创建主机
            result = self.api_manager.create_host(host_data)

            if result['success']:
                zabbix_host_id = result['data']['hostids'][0]

                # 创建监控记录
                monitoring_host = MonitoringHost.objects.create(
                    host=host,
                    zabbix_server=self.zabbix_server,
                    zabbix_host_id=zabbix_host_id,
                    zabbix_host_name=host.hostname,
                    monitoring_status='monitoring',
                    last_check_time=timezone.now()
                )

                return {
                    'hostname': host.hostname,
                    'status': 'success',
                    'action': 'created',
                    'message': '主机创建成功',
                    'zabbix_host_id': zabbix_host_id
                }
            else:
                return {
                    'hostname': host.hostname,
                    'status': 'error',
                    'message': f"创建Zabbix主机失败: {result.get('error')}"
                }

        except Exception as e:
            logger.error(f"创建Zabbix主机 {host.hostname} 失败: {e}")
            return {
                'hostname': host.hostname,
                'status': 'error',
                'message': str(e)
            }

    def _get_or_create_default_hostgroup(self) -> Optional[Dict[str, Any]]:
        """
        获取或创建默认主机组

        Returns:
            主机组信息
        """
        try:
            if not self.api_manager._connect():
                logger.error("无法连接到Zabbix服务器")
                return None

            # 先尝试获取现有的主机组
            try:
                groups = self.api_manager.zapi.hostgroup.get(
                    output='extend',
                    filter={'name': 'DevOps Platform Hosts'}
                )

                if groups and len(groups) > 0:
                    logger.info(f"找到现有主机组: {groups[0]['name']}")
                    return groups[0]
            except Exception as e:
                logger.warning(f"查询主机组失败: {e}")

            # 如果不存在，创建新的主机组
            try:
                create_result = self.api_manager.zapi.hostgroup.create(
                    name='DevOps Platform Hosts'
                )

                if create_result and 'groupids' in create_result:
                    group_id = create_result['groupids'][0]
                    logger.info(f"创建新主机组成功: ID={group_id}")
                    return {
                        'groupid': group_id,
                        'name': 'DevOps Platform Hosts'
                    }
            except Exception as e:
                logger.error(f"创建主机组失败: {e}")

            return None

        except Exception as e:
            logger.error(f"获取或创建默认主机组失败: {e}")
            return None

    def _get_default_templates(self) -> List[Dict[str, str]]:
        """
        获取默认模板列表

        Returns:
            模板列表
        """
        try:
            # 获取Linux服务器模板
            templates_result = self.api_manager._make_request('template.get', {
                'output': ['templateid', 'host'],
                'filter': {'host': ['Template OS Linux by Zabbix agent']}
            })

            # 处理API返回格式
            if templates_result and 'result' in templates_result and len(templates_result['result']) > 0:
                template_id = templates_result['result'][0]['templateid']
                logger.info(f"找到默认模板: Template OS Linux by Zabbix agent (ID: {template_id})")
                return [{'templateid': template_id}]
            elif templates_result and isinstance(templates_result, list) and len(templates_result) > 0:
                template_id = templates_result[0]['templateid']
                logger.info(f"找到默认模板: Template OS Linux by Zabbix agent (ID: {template_id})")
                return [{'templateid': template_id}]

            logger.warning("未找到默认模板: Template OS Linux by Zabbix agent")
            return []

        except Exception as e:
            logger.warning(f"获取默认模板失败: {e}")
            return []

    def sync_monitoring_status_to_cmdb(self) -> Dict[str, Any]:
        """
        同步监控状态到CMDB

        Returns:
            同步结果
        """
        try:
            monitoring_hosts = MonitoringHost.objects.filter(
                zabbix_server=self.zabbix_server,
                monitoring_status='monitoring'
            )

            updated_count = 0
            error_count = 0
            results = []

            for monitoring_host in monitoring_hosts:
                try:
                    result = self._update_host_monitoring_status(monitoring_host)
                    results.append(result)

                    if result['status'] == 'success':
                        updated_count += 1
                    else:
                        error_count += 1

                except Exception as e:
                    error_result = {
                        'hostname': monitoring_host.host.hostname,
                        'status': 'error',
                        'message': str(e)
                    }
                    results.append(error_result)
                    error_count += 1

            return {
                'success': True,
                'data': {
                    'total_hosts': len(monitoring_hosts),
                    'updated_count': updated_count,
                    'error_count': error_count,
                    'results': results
                },
                'message': f'状态同步完成，更新: {updated_count}, 失败: {error_count}'
            }

        except Exception as e:
            logger.error(f"同步监控状态失败: {e}")
            return {
                'success': False,
                'error': str(e)
            }

    def _update_host_monitoring_status(self, monitoring_host: MonitoringHost) -> Dict[str, Any]:
        """
        更新单个主机的监控状态

        Args:
            monitoring_host: 监控主机实例

        Returns:
            更新结果
        """
        try:
            # 获取Zabbix中的主机状态
            hosts_result = self.api_manager.get_hosts(
                hostids=[monitoring_host.zabbix_host_id]
            )

            if not hosts_result['success'] or not hosts_result['data']:
                return {
                    'hostname': monitoring_host.host.hostname,
                    'status': 'error',
                    'message': '无法获取Zabbix主机状态'
                }

            zabbix_host = hosts_result['data'][0]
            availability = zabbix_host.get('available', '0')

            # 更新监控主机状态
            monitoring_host.availability = availability
            monitoring_host.last_check_time = timezone.now()

            # 根据Zabbix状态更新CMDB主机状态
            cmdb_host = monitoring_host.host
            old_status = cmdb_host.status

            if availability == '1':  # Available
                new_status = 'online'
            elif availability == '2':  # Unavailable
                new_status = 'offline'
            else:  # Unknown
                new_status = 'offline'

            status_changed = False
            if old_status != new_status:
                cmdb_host.status = new_status
                cmdb_host.save(update_fields=['status'])
                status_changed = True

            monitoring_host.save(update_fields=['availability', 'last_check_time'])

            return {
                'hostname': monitoring_host.host.hostname,
                'status': 'success',
                'old_status': old_status,
                'new_status': new_status,
                'status_changed': status_changed,
                'availability': availability
            }

        except Exception as e:
            logger.error(f"更新主机 {monitoring_host.host.hostname} 监控状态失败: {e}")
            return {
                'hostname': monitoring_host.host.hostname,
                'status': 'error',
                'message': str(e)
            }
